#include "business_def.h"

#include <stdlib.h>
#include <iostream>

#include "record_queue.h"
#include "pfunc.h"
#include "Log.h"

namespace GlobalVar {
	std::string m_app_conf_file  = "appconf.xml";
};

// bool comp_dev(const Dev &a, const Dev &b) {
// 	return a.devInfo.desc < b.devInfo.desc;
// };
/////////////////////////////////////////////////////////
BusinessDef* BusinessDef::instance = NULL;
BusinessDef* BusinessDef::getInstance()
{
    if(NULL == BusinessDef::instance)
    {
        BusinessDef::instance = new BusinessDef();
    }
    return BusinessDef::instance;
}

BusinessDef::BusinessDef()
	: HorizontalData()
	, AppConfData()
{
	init();
};
void BusinessDef::Destroy()
{
	if(NULL!=BusinessDef::instance)
	{
		delete BusinessDef::instance;
		BusinessDef::instance = NULL;
	}
}

BusinessDef::~BusinessDef()
{
	this->Destroy();
}

void BusinessDef::init()
{
	pyfree::readAppConf(appConf,GlobalVar::m_app_conf_file);
	CLogger::createInstance()->Log(MsgInfo, "load %s finish!", GlobalVar::m_app_conf_file.c_str());
	//
	pyfree::readDevs(devs, appConf.bsconf.devPath);
	CLogger::createInstance()->Log(MsgInfo, "load %s finish!", appConf.bsconf.devPath.c_str());
	//
	pyfree::readPMaps(pmaps, appConf.bsconf.pmapPath);
	CLogger::createInstance()->Log(MsgInfo, "load %s finish!", appConf.bsconf.pmapPath.c_str());
	std::cout << "create point map!" << std::endl;
	for (std::vector<pyfree::PMap>::iterator it = pmaps.begin(); it!=pmaps.end();++it)
	{
		getAdditionalInfo(it->to.devID, it->to.pID,it->from.devDesc,it->from.pDesc,it->from.eway);
		it->to.devDesc = it->from.devDesc;
		it->to.pDesc = it->from.pDesc;
		it->to.eway = it->from.eway;
		ftmap.insert(KeyObj_FT(it->from.ipStr,it->from.pID,it->from.pType),it->to);
		tfmap.insert(KeyObj_TF(it->to.devID,it->to.pID), it->from);
	}
	if (ftmap.size()!= tfmap.size())
	{
		CLogger::createInstance()->Log(MsgWarn
			, "point map config error,the ftmap.size=%d,tfmap=%d,please check your config file map.xml!"
			, ftmap.size(), tfmap.size());
	}
	std::cout << "load plan conf start!" << std::endl;
	pyfree::readPlans(plans, appConf.bsconf.planPath);
	CLogger::createInstance()->Log(MsgInfo, "load %s finish!", appConf.bsconf.planPath.c_str());
	if (this->getAlarmFunc()) 
	{
		pyfree::readAlarms(alarms, appConf.bsconf.alarmPath);
		CLogger::createInstance()->Log(MsgInfo, "load %s finish!", appConf.bsconf.alarmPath.c_str());
		//增加描述字段,为了短信可采用描述信息
		pyfree::EventWay eway_ = pyfree::AlarmForDef;
		for (size_t i = 0, ASize=alarms.size(); i < ASize; i++)
		{
			for (size_t j = 0,CmdSize= alarms.at(i).alarmCmds.size(); j < CmdSize; j++)
			{
				getAdditionalInfo(alarms.at(i).alarmCmds[j].devID, alarms.at(i).alarmCmds[j].pID
					, alarms.at(i).alarmCmds[j].devDesc, alarms.at(i).alarmCmds[j].pDesc, eway_);
			}
		}
	}
	ptr_rq = RecordQueue::getInstance();
	//
	queueforwar = QueueDataSingle<EventForWaring>::getInstance();
	//
	queueforwrite_local = QueueDataSingle<SocketLocalWriteItem>::getInstance();
	//
	queueforwrite_aliyun = QueueDataSingle<SocketAliyunWriteItem>::getInstance();
	queueforwrite_aliyun->setQueueDesc("to_aliyun_data");
	//
	queueforwrite_mqtt = QueueDataSingle<SocketMqttWriteItem>::getInstance();
	queueforwrite_mqtt->setQueueDesc("to_mqtt_data");
};

//来自下层应用推送数据设值
bool BusinessDef::setValue(std::string _ipStr, int _id, pyfree::PType _pType, float _val, unsigned long _taskID)
{
	// printf("setValue(1):ip(%s),id(%d),ptype(%d),val(%.3f)\n",_ipStr.c_str(),_id,_pType,_val);
	bool ret = false;
	pyfree::PTo _pto;
	//优先获取对本层级的映射信息
	if (getToInfo(_ipStr,_id,_pType, _pto))
	{
		// printf("setValue(2):ip(%s),id(%d),ptype(%d),val(%.3f)\n",_ipStr.c_str(),_id,_pType,_val);
		PValueRet pret(_val);
		ret = setHValue(_pto.devID, _pto.pID, pret);
		//
		unsigned int _usec = pyfree::getUsec();
		//转发
		if (pret.sendflag|| pret.sendflag_ali)
		{
			// printf("setValue(3):ip(%s),id(%d),ptype(%d),val(%.3f)\n",_ipStr.c_str(),_id,_pType,_val);	
			DataToThird _wdlc(static_cast<unsigned long long>(_pto.devID), _pto.pID, _pto.pType
				, static_cast<unsigned int>(time(NULL))
				, _usec, pret.val_actual);
			//转发其他
			if (pret.sendflag) {
				send_data_to_third(_wdlc);
			}
			//转发阿里,其轮询间隔时间较长,节省流量,为了省钱
			if (pret.sendflag_ali) {
				send_data_to_third(_wdlc, true);
			}
		}
		//记录
		if (pret.recordflag&&this->getRecordFunc())
		{
			//printf("setValue(4):ip(%s),id(%d),ptype(%d),val(%.3f)\n",_ipStr.c_str(),_id,_pType,_val);
			ptr_rq->addItem(static_cast<long>(_pto.devID), _pto.pID
				, static_cast<long long>(1000 * time(NULL)) + static_cast<long long>(_usec)
				, pret.val_actual);
		}
		//告警
		if (pret.waringflag&&this->getWaringEventFunc()) 
		{
			//waring;
			EventForWaring event_;
			//
			event_.grade	= majorLevel;
			event_.send_	= pret.eway_;
			event_.execTime = pyfree::getCurrentTimeByFormat("%04d%02d%02dT%02d%02d%02dZ");//短信平台要求格式
			event_.taskID	= _taskID;
			event_.taskDesc = "LiveUpdate";
			event_.devID	= static_cast<unsigned long>(_pto.devID);
			event_.devDesc	= pret.devDesc;
			event_.pID		= _pto.pID;
			event_.pDesc	= pret.pDesc;
			//值状况描述,阿里短信接口限定变量字段20以内
			char buf_val[64] = { 0 };
			sprintf(buf_val, "A(%.1f)", pret.val_actual);
			event_.valDesc	= std::string(buf_val);
			//全状况描述
			char buf_comment[512] = { 0 };
			for (size_t i = 0,eSize = pret.evts.size(); i < eSize; ++i)
			{
				event_.type = pret.evts.at(i);
				switch (event_.type)
				{
				case YCUpOverLimit:
					sprintf(buf_comment
						, "LiveUpdate VerificationForPValue taskID(%lu),from(%s,%d,%d,%.2f)"
						",setValue devID(%lld),devDesc(%s),pID(%d),pDesc(%s),pType(%d),actual_value(%.2f)"
						",upLimit(%.2f)"
						, _taskID, _ipStr.c_str(), _id, static_cast<int>(_pType), _val
						, _pto.devID, pret.devDesc.c_str()
						, _pto.pID, pret.pDesc.c_str(), static_cast<int>(_pto.pType)
						, pret.val_actual
						, pret.val_limitUp);
					break;
				case YCDownOverLimit:
					sprintf(buf_comment
						, "LiveUpdate VerificationForPValue taskID(%lu),from(%s,%d,%d,%.2f)"
						",setValue devID(%lld),devDesc(%s),pID(%d),pDesc(%s),pType(%d),actual_value(%.2f)"
						",downLimit(%.2f)"
						, _taskID, _ipStr.c_str(), _id, static_cast<int>(_pType), _val
						, _pto.devID, pret.devDesc.c_str()
						, _pto.pID, pret.pDesc.c_str(), static_cast<int>(_pto.pType)
						, pret.val_actual
						, pret.val_limitDown);
					break;
				case YCBreak:
					sprintf(buf_comment
						, "LiveUpdate VerificationForPValue taskID(%lu),from(%s,%d,%d,%.2f)"
						",setValue devID(%lld),devDesc(%s),pID(%d),pDesc(%s),pType(%d),actual_value(%.2f)"
						",oldVal(%.2f),ComBaseVal(%.2f),ComRate(%.2f)"
						, _taskID, _ipStr.c_str(), _id, static_cast<int>(_pType), _val
						, _pto.devID, pret.devDesc.c_str()
						, _pto.pID, pret.pDesc.c_str(), static_cast<int>(_pto.pType)
						, pret.val_actual
						, pret.val_old, pret.val_base, pret.val_rate);
					break;
				case YCDisturb:case YXShake:
					sprintf(buf_comment
						, "LiveUpdate VerificationForPValue taskID(%lu),from(%s,%d,%d,%.2f)"
						",setValue devID(%lld),devDesc(%s),pID(%d),pDesc(%s),pType(%d),actual_value(%.2f)"
						",oldVal(%.2f),shakeInterval(%u)"
						, _taskID, _ipStr.c_str(), _id, static_cast<int>(_pType), _val
						, _pto.devID, pret.devDesc.c_str()
						, _pto.pID, pret.pDesc.c_str(), static_cast<int>(_pto.pType)
						, pret.val_actual
						, pret.val_old, pret.shake_interval);
					break;
				default:
					sprintf(buf_comment, "%s", "unkown event type");
					break;
				}
				event_.Comment = std::string(buf_comment);
				queueforwar->add(event_);
			}
			//CLogger::createInstance()->Log(eTipMessage, "%s", buf_comment);
		}
		if (_taskID > 0) 
		{
			CLogger::createInstance()->Log(MsgInfo,
				"TaskID[%lu] and up_node[5] BusinessDef::setValue ip(%s),pID(%d),pType(%d),Val(%.2f) "
				"getPTO_Map devID(%ld),pID(%d),pType(%d),Val(%.2f)"
				",sendflag[%d],recordflag[%d],waringflag[%d]."
				, _taskID, _ipStr.c_str(), _id, static_cast<int>(_pType), _val
				, _pto.devID, _pto.pID, static_cast<int>(_pto.pType), pret.val_actual
				, static_cast<int>(pret.sendflag)
				, static_cast<int>(pret.recordflag)
				, static_cast<int>(pret.waringflag));
		}
	}
	else {
		if (_taskID>0)
		{
			CLogger::createInstance()->Log(MsgInfo,
				"TaskID[%lu] and up_node[5-1] BusinessDef::setValue ip(%s),pID(%d),pType(%d),Val(%.2f)  "
				"getPTO_map fail. [%s %s %d]"
				, _taskID, _ipStr.c_str(),_id, static_cast<int>(_pType), _val
				, __FILE__, __FUNCTION__, __LINE__);
		}
	}
	return ret;
};


bool BusinessDef::getFromInfo(unsigned long long _devID, unsigned int _pID,pyfree::PFrom &_pfrom)
{
	return tfmap.getVal(KeyObj_TF(_devID, _pID), _pfrom);
}

bool BusinessDef::getToInfo(std::string _ipStr, int _id, pyfree::PType _pType,pyfree::PTo &_pto)
{
	return ftmap.getVal(KeyObj_FT(_ipStr,_id,_pType), _pto);
}

void BusinessDef::TimeUpVirtualPInfo()
{
	if (!this->getTimeUpFunc())
		return;
	TimeUpVirtual();//HorizontalData::
}
//将长期无变化和长期不刷新的判定移到独立线程处理，不占用数据接收处理逻辑时间
void BusinessDef::TimeCheckPInfo()
{
	if (!this->getWaringEventFunc())
		return;
	TimeCheck();//HorizontalData::
}

void BusinessDef::send_data_to_third(const DataToThird &_wdlc,bool ali_flag)
{
	if (ali_flag) 
	{
		//云端阿里云物联网平台
		if (this->getAliyunIOFunc())
		{
			queueforwrite_aliyun->add(SocketAliyunWriteItem(_wdlc));
		}
	}else {
		//本地SOCKET客户端
		if (this->getLocalSocketFunc())
		{
			// printf("********************devid:%llu,pid:%d,val:%f****************************\n"
			// 	,_wdlc.devID,_wdlc.pID,_wdlc.val);
			queueforwrite_local->add(SocketLocalWriteItem(_wdlc));
		}
		if(this->getMqttFunc())
		{
			queueforwrite_mqtt->add(SocketMqttWriteItem(_wdlc));
		}
	}
}

void BusinessDef::add_event(EventForWaring event_)
{
	queueforwar->add(event_);
}